package main

import (
	"fmt"
)

//Part1.
// 接口是一种类型，是一种抽象的类型
// type dog struct{}

// func (d dog) say() {
// 	fmt.Println("汪汪汪~")
// }

// type cat struct{}

// func (c cat) say() {
// 	fmt.Println("喵喵喵~")
// }

// type person struct {
// 	name string
// }

// func (p person) say() {
// 	fmt.Println("啊啊啊~")
// }

// // 接口不管你是什么类型，它只管你要实现什么方法
// // 定义一个类型，一个抽象的类型，只要是实现了say()这个方法的类型都可以称为sayer类型
// type sayer interface {
// 	say()
// }

// // 打的函数 - 把接口的类型传入函数
// func da(arg sayer) {
// 	arg.say() //不管传进来的是什么，我都要打ta，打ta，ta就会叫，就会执行ta的say方法
// }

// func main() {
// 	c1 := cat{}
// 	da(c1)
// 	d1 := dog{}
// 	da(d1)
// 	p1 := person{
// 		name: "娜扎",
// 	}
// 	da(p1)

// 	var s sayer
// 	c2 := cat{}
// 	s = c2
// 	p2 := person{name: "小王子"}
// 	s = p2
// 	fmt.Println(s)
// }

//Part2.
// 使用值接收者实现接口和使用指针接收者实现接口的区别

// 接口的嵌套
// type animal interface {
// 	mover
// 	sayer
// }
// type mover interface {
// 	move()
// }
// type sayer interface {
// 	say()
// }
// type person struct {
// 	name string
// 	age  int8
// }

// 使用值接收者实现接口 - 类型的值和类型指针都能保存到接口变量中
// func (p person) move() {
// 	fmt.Printf("%s在跑...\n", p.name)
// }

// func main() {
// 	var m mover
// 	p1 := person{ //person类型的值
// 		name: "小王子",
// 		age:  18,
// 	}
// 	p2 := &person{ //p2是person类型的指针
// 		name: "娜扎",
// 		age:  18,
// 	}
// 	m = p1
// 	m = p2
// 	m.move()
// 	fmt.Println(m)
// }

// 使用指针接收者实现接口 - 只有类型指针能够保存到接口变量中
// func (p *person) move() {
// 	fmt.Printf("%s在跑...\n", p.name)
// }

// func (p *person) say() {
// 	fmt.Printf("%s在叫...\n", p.name)
// }

// func main() {
// 	var m mover //定义一个mover类型的变量
// 	// p1 := person{ //person类型的值
// 	// 	name: "小王子",
// 	// 	age:  18,
// 	// }
// 	p2 := &person{ //p2是person类型的指针
// 		name: "娜扎",
// 		age:  18,
// 	}
// 	//m = p1 // ？无法赋值，因为p1是person类型的值没有实现mover接口
// 	m = p2
// 	m.move()
// 	fmt.Println(m)

// 	var s sayer //定义一个sayer类型的变量
// 	s = p2
// 	s.say()
// 	fmt.Println(s)

// 	var a animal //定义一个animal类型的变量
// 	a = p2
// 	a.move()
// 	a.say()
// 	fmt.Println(a)
// }

//Part3.
//空接口
//接口中没有定义任何需要实现的方法时，该接口就是一个空接口
//任意类型都实现了空接口 --> 空接口变量可以存储任意值！

// 空接口一般不需要提前定义
type xxx interface{}

// 空接口的应用
// 1.空接口类型作为函数的参数
// 2.空接口可以作为map的value
func main() {
	var x interface{} //定义一个空接口
	x = "hello"
	fmt.Println(x)
	x = 100
	fmt.Println(x)
	x = false
	fmt.Println(x)

	// var m =make(map[string]interface{},16)
	// m["name"] = "娜扎"
	// m["age"] = 18
	// m["hobby"] = []string{"篮球","足球","双色球"}
	// fmt.Println(m)

	//判断空接口中存储的值的类型
	//类型断言

	// ret := x.(bool) //类型断言
	// fmt.Printf("ret: %v\n", ret)
	ret, ok := x.(string) //类型断言,猜的类型不对时，会返回一个布尔值
	if !ok {
		fmt.Println("不是字符串类型")
	} else {
		fmt.Printf("是字符串类型", ret)
	}

	//使用switch进行类型断言
	switch v := x.(type) {
	case string:
		fmt.Printf("是字符串类型，value:%v\n", v)
	case bool:
		fmt.Printf("是布尔类型，value:%v\n", v)
	case int:
		fmt.Printf("是int类型，value:%v\n", v)
	default:
		fmt.Printf("猜不到了，value:%v\n", v)

	}
}
